package com.msun.auth.apiOpen.aop;

import com.alibaba.fastjson.JSONObject;
import com.msun.auth.apiOpen.OpenContext;
import com.msun.auth.custom.exception.BizException;
import com.msun.auth.utils.LogUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description //TODO
 * @Date 2023/8/18 19:22
 * @Author guijie
 **/
@Slf4j
@Aspect
@Component
public class OpenLogAspect {
    private static final ThreadLocal<LogInfo> context = new ThreadLocal<>();

    @Data
    public static class LogInfo {
        private String url;
        private String method;
        private String classMethod;
        private String ip;
        private String reqArgs;
        private String respBody;
        private String duration;
        private OpenContext.Context ctx;
    }

    /**
     * 以 controller 包下定义的所有请求为切入点
     */
    @Pointcut("execution(public * com.msun.auth.apiOpen.handler.*.*(..))")
    public void webLog() {
    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        LogInfo logInfo = new LogInfo();
        logInfo.setUrl(request.getRequestURL().toString());
        logInfo.setMethod(request.getMethod());
        logInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()));
        logInfo.setIp(request.getRemoteAddr());
        logInfo.setReqArgs(JSONObject.toJSONString(joinPoint.getArgs()));
        context.set(logInfo);
    }

    /**
     * 在切点之后织入
     *
     * @throws Throwable
     */
    @After("webLog()")
    public void doAfter() {
        log.info("");
    }

    /**
     * 环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        OpenContext.Context ctx = OpenContext.get();
        Object result;
        try {
            //切入
            result = proceedingJoinPoint.proceed();
        } catch (BizException e) {
            e.printStackTrace();
            OpenLogAspect.LogInfo logInfo = context.get();
            logInfo.setDuration((System.currentTimeMillis() - startTime) + " ms");

            LogUtils.apiErr(logInfo.getUrl(), logInfo.getReqArgs(), e.getE(), ctx);
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            LogInfo logInfo = context.get();
            logInfo.setDuration((System.currentTimeMillis() - startTime) + " ms");
            LogUtils.apiErr(logInfo.getUrl(), logInfo.getReqArgs(), e, ctx);
            throw e;
        } finally {
            LogInfo logInfo = context.get();
//            if (result != null) {
//                logInfo.setRespBody(JSONObject.toJSONString(result));
//            }
//            logInfo.setDuration((System.currentTimeMillis() - startTime) + " ms");
//            LogUtils.mixInfo(logInfo);
            log.info(logInfo.getUrl() + "耗时：" + (System.currentTimeMillis() - startTime) + " ms");
            context.remove();
        }
        return result;
    }
}
